#pragma once
#include <vector>
#include <mutex>
#include <iostream>
#include "eventable_bool.h"

//---------------------------------------------------------------------------

/**
 * Ring of fairness!
 */
class ring
{
public:
	enum class ring_states : byte
	{
		active_group_0	= 0,
		active_group_1	= 1,
		active			= 2,
		inactive		= 3
	};

	struct thread_state
	{
		thread_state()
		{
			_is_assigned_or_inactive = std::make_shared<eventable_bool>();
			_is_group_0				 = std::make_shared<eventable_bool>();
			_is_group_1				 = std::make_shared<eventable_bool>();
		}

		~thread_state() = default;

		void operator = (ring_states rstate)
		{
			_state = rstate;

			switch(rstate)
			{
				case ring_states::inactive:
					*_is_assigned_or_inactive = true;
					*_is_group_0 = false;
					*_is_group_1 = false;
				break;

				case ring_states::active:
					*_is_assigned_or_inactive = false;
					*_is_group_0 = false;
					*_is_group_1 = false;
				break;

				case ring_states::active_group_0:
					*_is_assigned_or_inactive = true;
					*_is_group_0 = true;
					*_is_group_1 = false;
				break;

				case ring_states::active_group_1:
					*_is_assigned_or_inactive = true;
					*_is_group_0 = false;
					*_is_group_1 = true;
				break;
			}
		}

		operator ring_states(){ return _state; }
		
		ring_states		_state = ring_states::inactive;
		std::shared_ptr<eventable_bool>	_is_assigned_or_inactive;
		std::shared_ptr<eventable_bool>	_is_group_0;
		std::shared_ptr<eventable_bool>	_is_group_1;
	};

public:
	ring()
	{
		/*
		_is_waiting_group_0 = true;
		_is_waiting_group_1 = false;
		*/

		_waiting_group = false;
	}
	virtual ~ring() = default;

	void register_to_ring();

	template<typename _FairFunc>
	void operator()(_FairFunc& fair_section)
	{
		pre();

		// call fair section
		fair_section();

		post();
	}

protected:
	void pre(void);
	void post(void);
	
private:
	static __declspec(thread) int		_loop_index;
	static __declspec(thread) int		_thread_index;
	static __declspec(thread) HANDLE	_thread_wait[2];
	static __declspec(thread) DWORD		_wait_object_result;
	std::vector<thread_state>			_states;
	waiting_group_bool					_waiting_group; // false - group 0 ; true - group 1
	std::mutex							_registration_lock;

//	eventable_bool						_is_waiting_group_0;
//	eventable_bool						_is_waiting_group_1;
};
//---------------------------------------------------------------------------
